﻿using System;
using System.Collections;
using System.Net;
using System.IO;
using System.Threading;

namespace Spider
{
    public class Spider
    {
        public Hashtable m_already;//保存获得的url
        private Queue m_workload;  //保存要处理的url
        private Uri m_base;
        private FrmMain m_spiderForm;
        public int m_urlCount = 0;   //处理的url数量
        public int m_urlFailCount = 0;//失败的url数量
        public long m_startTime = 0;
        private Done m_done = new Done();
        private bool m_quit;
        DocumentWorker worker;

        enum Status
        {
            STATUS_FAILED, STATUS_SUCCESS, STATUS_QUEUED
        };
        public Spider()
        {
            reset();
        }
        public void reset()
        {
            m_already = new Hashtable();
            m_workload = new Queue();
            m_quit = false;
        }
        public void addURI(Uri uri)
        {
            uri = new Uri(uri.ToString().Replace("///", "/"));
            uri = new Uri(uri.ToString().Replace("////", "/"));
            Monitor.Enter(this);
            if (!m_already.Contains(uri))
            {
                m_already.Add(uri, Status.STATUS_QUEUED);
                m_workload.Enqueue(uri);
            }
            Monitor.Pulse(this);  //往队列里添加一个uri之后，就通知等待的线程
            Monitor.Exit(this);
        }
        public Uri BaseURI
        {
            get { return m_base; }
            set { m_base = value; }
        }

        public FrmMain ReportTo
        {
            get { return m_spiderForm; }
            set { m_spiderForm = value; }
        }
        public bool Quit
        {
            get { return m_quit; }
            set { m_quit = value; }
        }
        public Done SpiderDone
        {
            get { return m_done; }
        }
        public Uri ObtainWork()
        {
            Monitor.Enter(this);
            while (m_workload.Count < 1) //当队列中的元素数小于1时，就阻塞当前线程
            {
                Monitor.Wait(this);
            }
            Uri next = (Uri)m_workload.Dequeue();  //得到开始位置处的对象，并移除它
            Monitor.Exit(this);
            return next;
        }
        public void Start(Uri baseURI, int threads)  //程序运行中，只执行一次
        {
            m_quit = false;
            m_base = baseURI;
            addURI(baseURI);
            for (int i = SpiderAccount.StartListPage; i <= SpiderAccount.EndListPage; i++)
            {
                addURI(new Uri(SpiderAccount.TemplateUrl.Replace("[1]", i.ToString())));
            }

            m_startTime = DateTime.Now.Ticks;
            m_done.Reset(); //设置活动线程数是0

            //蜘蛛程序允许用户自己确定要使用的线程数量。在实践中，线程的最佳数量受许多因素影响。
            //如果你的机器性能较高，或者有两个处理器，可以设置较多的线程数量；
            //  反之，如果网络带宽、机器性能有限，设置太多的线程数量其实不一定能够提高性能。

            worker = new DocumentWorker(this);
            worker.StartThread();
            //for (int i = 1; i < threads + 1; i++)
            //{
            //    DocumentWorker worker = new DocumentWorker(this);
            //    worker.Number = i;
            //    worker.StartThread();
            //}
            m_done.WaitBegin();
            m_done.WaitDone();

            System.Windows.Forms.MessageBox.Show("所有下载完毕！   ^_^");
            m_spiderForm.DownloadComplete(); //隐藏正在运行的图片
        }
        /// <summary>
        /// 终止所有线程
        /// </summary>
        public void Stop()
        {
            worker.StopThread();
        }
        /// <summary>
        /// 此类有个FraMain的实例，所有在这里写了个方法
        /// </summary>
        /// <param name="url"></param>
        public void ShowUrl(int fileoffset, string url, string title, bool color)
        {
            ReportTo.ShowLog(fileoffset, url, title, color);
        }
    }
}
